package xj.graph2d.app.prop;

import static xj.app.BaseApplicationFrame.getResourceString;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;

import javax.swing.JFrame;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;

import xj.graph2d.table.FeatureTable;
import xj.graph2d.table.FeatureTableEntry;
import xj.meta.Link;
import xj.model.uml.BasicModelElement;
import xj.model.uml.NamedElement;

public class LinkField extends FeatureListField {

  public LinkField() {
    super();
    if (editor != null) {
      editor.setToolTipText(getResourceString("Links.edit.tip"));
    }
  }

  public LinkField(JFrame owner) {
    super(owner, getResourceString("Links.text"),
	  getResourceString("Links.dialog.title"),
	  false, false);
    if (editor != null) {
      editor.setToolTipText(getResourceString("Links.edit.tip"));
    }
  }

  @Override
  protected void updateTips() {
    if (editor != null) {
      String prefix = "<html><body bgcolor='white'><b>Links</b><br>";
      String suffix = "</body></html>";
      String text = null;
      if (model != null) {
	Set<Link> links = model.getLinks();
	if (links != null && !links.isEmpty()) {
	  StringBuilder sb = new StringBuilder();
	  Iterator<Link> iter = links.iterator();
	  while (iter.hasNext()) {
	    sb.append("&nbsp;&nbsp;");
	    Link link = iter.next();
	    sb.append(link.getName() + ": " + link.getLink());
	    sb.append("<br>");
	  }
	  text = sb.toString();
	}
      }
      if (text == null) { 
	text = "&nbsp;&nbsp;<i>none</i>";
      }
      editor.setToolTipText(prefix + text + suffix);
    }
  }

  @Override
  public void updateEditorValue() {
    java.util.List<FeatureTableEntry> entries = featurePanel.getEntries();
    if (entries != null) {
      entries.clear();
    } else {
      entries = new ArrayList<FeatureTableEntry>();
    }
    if (model != null) {
      Set<Link> links = model.getLinks();
      if (links != null) {
	Iterator<Link> iter = links.iterator();
	while (iter.hasNext()) {
	  Link link = iter.next();
	  entries.add(new LinkEntry(link.getName(), link.getLink()));
	}
      }
    }
    if (entries.isEmpty()) {
      entries.add(makeNewEntry());
    }
    featurePanel.setEntries(entries);

    if (featureDialog != null) {
      String name = null;
      String element = null;
      if (model instanceof NamedElement) {
	name = ((NamedElement) model).getName();
      }
      if (name == null || name.length() == 0) {
	name = "<unnamed>";
      }
      element = "[" + model.getElementName() + "]";
      featurePanel.setTableTitle("Links of", name, element);
    }
  }

  @Override
  public void updateModelValue() {
    java.util.List<FeatureTableEntry> entries = featurePanel.getEntries();
    if (model != null) {
      model.removeAllLinks();
      if (entries != null) {
	Iterator<FeatureTableEntry> iter = entries.iterator();
	while (iter.hasNext()) {
	  FeatureTableEntry fe = iter.next();
	  if (fe instanceof LinkEntry) {
	    LinkEntry entry = (LinkEntry) fe;
	    String name = entry.getName();
	    String reference = entry.getReference();
	    if (name != null && name.length() > 0 && reference != null
		&& reference.length() > 0) {
	      model.addLink(name, reference);
	    }
	  }
	}
      }
      updateTips();
    }
  }

  static FeatureTableEntry proto = new LinkEntry();

  @Override
  public FeatureTableEntry getPrototype() {
    return proto;
  }

  @Override
  public FeatureTableEntry makeNewEntry() {
    return new LinkEntry();
  }

}

class LinkEntry implements FeatureTableEntry {

  // position of each column
  public static final int NAME_COLUMN = 0;

  public static final int REFERENCE_COLUMN = 1;

  public static final int DELETE_COLUMN = 2;

  public static final String[] columnNames = { "Name", "Reference", "Delete", };

  public static final String[] columnTips = { "Name of the link",
      "Reference of the link", "Delete the marked link", };

  public static final Comparator[] comparators = {
      new FeatureEntryComparator(NAME_COLUMN),
      new FeatureEntryComparator(REFERENCE_COLUMN), null, };

  public static TableCellEditor[] editors = new TableCellEditor[3];

  public static TableCellRenderer[] renderers = { null, null,
      new FeatureTable.GrayBooleanRenderer(), // for Delete
  };

  public static final int[] columnWidths = { 50, 50, 20, };

  public LinkEntry() {
  }

  public LinkEntry(String name, String reference) {
    this.name = name;
    this.reference = reference;
  }

  public int getColumnCount() {
    return columnNames.length;
  }

  public String getColumnName(int col) {
    if (col >= 0 && col < columnNames.length) {
      return columnNames[col];
    }
    return null;
  }

  public Object getColumnValue(int col) {
    if (col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	return name;
      case REFERENCE_COLUMN:
	return reference;
      case DELETE_COLUMN:
	return deleted;
      }
    }
    return null;
  }

  public void setColumnValue(int col, Object v) {
    if (col >= 0 && col < columnNames.length) {
      switch (col) {
      case NAME_COLUMN:
	if (v != null) {
	  name = v.toString();
	} else {
	  name = null;
	}
	break;
      case REFERENCE_COLUMN:
	if (v != null) {
	  reference = v.toString();
	} else {
	  reference = null;
	}
	break;
      case DELETE_COLUMN:
	if (v instanceof Boolean) {
	  deleted = ((Boolean) v).booleanValue();
	}
	break;
      }
    }
  }

  public String getColumnTip(int col) {
    if (col >= 0 && col < columnTips.length) {
      return columnTips[col];
    }
    return null;
  }

  public Class getColumnClass(int col) {
    switch (col) {
    case NAME_COLUMN:
      return String.class;
    case REFERENCE_COLUMN:
      return String.class;
    case DELETE_COLUMN:
      return Boolean.class;
    default:
      return String.class;
    }
  }

  public Comparator getColumnComparator(int col) {
    if (col >= 0 && col < comparators.length) {
      return comparators[col];
    }
    return null;
  }

  public TableCellEditor getColumnEditor(int col) {
    if (col >= 0 && col < editors.length) {
      return editors[col];
    }
    return null;
  }

  public boolean isColumnEditable(int col) {
    if (col >= 0 && col < columnNames.length) {
      return true;
    }
    return false;
  }

  public TableCellRenderer getColumnRenderer(int col) {
    if (col >= 0 && col < renderers.length) {
      return renderers[col];
    }
    return null;
  }

  public int getColumnWidth(int col) {
    if (col >= 0 && col < columnWidths.length) {
      return columnWidths[col];
    }
    return -1;
  }

  public String getName() {
    return name;
  }

  public String getReference() {
    return reference;
  }

  public BasicModelElement getModelElement() {
    return null;
  }

  public boolean isDeleted() {
    return deleted;
  }

  public boolean isEditable() {
    return true;
  }

  protected String name, reference;

  protected boolean deleted;

  static public class FeatureEntryComparator implements Comparator {

    public FeatureEntryComparator(int col) {
      this.col = col;
    }

    public int compare(Object o1, Object o2) {
      if (o1 instanceof LinkEntry && o2 instanceof LinkEntry) {
	LinkEntry e1 = (LinkEntry) o1;
	LinkEntry e2 = (LinkEntry) o2;
	Object v1 = e1.getColumnValue(col);
	Object v2 = e2.getColumnValue(col);
	if (v1 != null && v2 != null) {
	  switch (col) {
	  case NAME_COLUMN:
	  case REFERENCE_COLUMN:
	    return (v1.toString()).compareTo(v2.toString());
	  default:
	    return ((String) v1).compareTo((String) v2);
	  }
	}
      }
      return 0;
    }

    protected int col;
  }

}
